home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / vm / vmSubr.c < prev    next >
C/C++ Source or Header  |  1991-07-26  |  46KB  |  1,648 lines

  1. /* vmSubr.c -
  2.  *
  3.  *     This file contains miscellaneous virtual memory routines.
  4.  *
  5.  * Copyright (C) 1985 Regents of the University of California
  6.  * All rights reserved.
  7.  */
  8.  
  9. #ifndef lint
  10. static char rcsid[] = "$Header: /sprite/src/kernel/vm/RCS/vmSubr.c,v 9.15 91/07/26 17:05:01 shirriff Exp $ SPRITE (Berkeley)";
  11. #endif not lint
  12.  
  13. #include <sprite.h>
  14. #include <vm.h>
  15. #include <vmInt.h>
  16. #include <vmTrace.h>
  17. #include <lock.h>
  18. #include <sync.h>
  19. #include <sys.h>
  20. #include <list.h>
  21. #include <dbg.h>
  22. #include <stdlib.h>
  23. #include <fs.h>
  24. #include <fsio.h>
  25. #include <stdio.h>
  26. #include <bstring.h>
  27. #include <assert.h>
  28. #include <vmHack.h>
  29. #ifdef sun4
  30. #include <machMon.h>
  31. #endif
  32. /*
  33.  * Declarations of external variables
  34.  */
  35.  
  36. Vm_Stat        vmStat;
  37. int             vmFirstFreePage;  
  38. Address        vmMemEnd;
  39. Sync_Lock     vmMonitorLock;
  40. Sync_Lock     vmShmLock;
  41. int        vmShmLockCnt = 0;
  42. int        vm_PageSize;
  43. int        vmPageShift;
  44. int        vmPageTableInc;
  45. int        vmKernMemSize;
  46. int        vmMaxProcesses = 80;
  47. Address        vmBlockCacheBaseAddr;
  48. Address     vmBlockCacheEndAddr;
  49. int        vmMaxMachSegs;
  50. extern Vm_SharedSegTable    sharedSegTable;
  51.  
  52. Boolean        vmDebugLargeAllocs = FALSE;
  53.  
  54. extern int debugVmStubs;    /* Unix compatibility flag. */
  55.  
  56. /*
  57.  * The maximum amount that a stack is allowed to grow.  We have to make it
  58.  * real big because of the current configuration of SPUR.  This can be made
  59.  * smaller once the exec stuff has changed.  Things are worse for the sun4
  60.  * due to the order in which user processes try to flush their register
  61.  * windows to a stack which hasn't been validated yet.
  62.  */
  63. #ifndef sun4
  64. #define    MAX_STACK_GROWTH_SIZE    (1024 * 1024 * 2)
  65. #else
  66. #define    MAX_STACK_GROWTH_SIZE    (1024 * 1024 * 8)
  67. #endif /* not sun4 */
  68. int        vmMaxStackPagesGrowth;
  69.  
  70. /*
  71.  * ----------------------------------------------------------------------------
  72.  *
  73.  * Vm_Init --
  74.  *
  75.  *     Initialize all virtual memory data structures.
  76.  *
  77.  * Results:
  78.  *     None.
  79.  *
  80.  * Side effects:
  81.  *     All virtual memory linked lists and arrays are initialized.
  82.  *
  83.  * ----------------------------------------------------------------------------
  84.  */
  85. void
  86. Vm_Init()
  87. {
  88.     register    Vm_PTE    *ptePtr;
  89.     int            i;
  90. #ifdef notdef
  91.     unsigned int    virtPage;
  92. #endif
  93.  
  94.     Sync_LockInitDynamic(&vmMonitorLock, "Vm:vmMonitorLock");
  95.     Sync_LockInitDynamic(&vmShmLock, "Vm:vmShmLock");
  96.  
  97.     /*
  98.      * Set up the maximum number of pages that a stack can grow.
  99.      */
  100.     vmMaxStackPagesGrowth = MAX_STACK_GROWTH_SIZE / vm_PageSize;
  101.     /*
  102.      * Partition up the kernel virtual address space.
  103.      */
  104.     vmStackBaseAddr = (Address) (mach_KernStart + vmKernMemSize);
  105.     vmStackEndAddr = vmStackBaseAddr + mach_KernStackSize * vmMaxProcesses;
  106.     vmMapBaseAddr = vmStackEndAddr;
  107.     vmMapBasePage = (unsigned int)vmMapBaseAddr / vm_PageSize;
  108.     vmMapEndAddr = vmMapBaseAddr + vmNumMappedPages * vm_PageSize;
  109.     vmMapEndPage = vmMapBasePage + vmNumMappedPages;
  110.     vmBlockCacheBaseAddr = VmMach_AllocKernSpace(vmMapEndAddr);
  111.     vmBlockCacheEndAddr = (Address)mach_KernEnd;
  112.     /*
  113.      * Allocate the segment table and core map.
  114.      */
  115.     VmSegTableAlloc();
  116.     VmCoreMapAlloc();
  117.     /*
  118.      * Initialize the structure for kernel stacks.
  119.      */
  120.     VmStackInit();
  121.     /*
  122.      * Allocate and initialize the kernel page table.
  123.      */
  124.     vm_SysSegPtr->ptSize = (mach_KernEnd - mach_KernStart) / vm_PageSize;
  125.     vm_SysSegPtr->ptPtr =
  126.         (Vm_PTE *)Vm_BootAlloc(sizeof(Vm_PTE) * vm_SysSegPtr->ptSize);
  127.  
  128.     bzero((Address)vm_SysSegPtr->ptPtr, sizeof(Vm_PTE) * vm_SysSegPtr->ptSize);
  129.  
  130.     /*
  131.      * Can no longer use Vm_BootAlloc
  132.      */
  133.     vmNoBootAlloc = TRUE;
  134.     /* 
  135.      * Determine how many physical pages that we have used.
  136.      */
  137.     vmFirstFreePage = 
  138.     (unsigned int)(vmMemEnd - mach_KernStart - 1) / vm_PageSize + 1;
  139.  
  140.     for (i = 0, ptePtr = vm_SysSegPtr->ptPtr;
  141.      i < vmFirstFreePage;
  142.      i++, ptePtr++) {
  143.     *ptePtr = VM_VIRT_RES_BIT | VM_PHYS_RES_BIT | i;
  144.     }
  145.     /*
  146.      * Initialize the segment table and core map.
  147.      */
  148.     VmSegTableInit();
  149.     VmCoreMapInit();
  150. #ifdef notdef
  151.     /*
  152.      * Take away the page at the bottom of the kernel stack.
  153.      */
  154.     virtPage = (mach_StackBottom - mach_KernStart) >> vmPageShift;
  155.     vm_SysSegPtr->ptPtr[virtPage] = 0;
  156.     VmPutOnFreePageList(virtPage);
  157. #endif
  158.     /*
  159.      * Now call the hardware dependent initialization routine.
  160.      */
  161.     VmMach_Init(vmFirstFreePage);
  162.  
  163. #ifdef VM_CHECK_BSTRING_ACCESS
  164.     /* 
  165.      * Initialize the debugging structures in vmMap.c
  166.      */
  167.     VmMapInit();
  168. #endif
  169. }
  170.  
  171.  
  172. /*
  173.  * ----------------------------------------------------------------------------
  174.  *
  175.  * Vm_ProcInit --
  176.  *
  177.  *     Initialize VM info for this process.
  178.  *
  179.  * Results:
  180.  *     None.
  181.  *
  182.  * Side effects:
  183.  *     Virtual memory information for the given process is initialized.
  184.  *
  185.  * ----------------------------------------------------------------------------
  186.  */
  187. void
  188. Vm_ProcInit(procPtr)
  189.     Proc_ControlBlock    *procPtr;
  190. {
  191.     int                i;
  192.     register    Vm_ProcInfo    *vmPtr;
  193.  
  194.     if (procPtr->vmPtr == (Vm_ProcInfo *)NIL) {
  195.     vmPtr = (Vm_ProcInfo *)malloc(sizeof(Vm_ProcInfo));
  196.     vmPtr->machPtr = (VmMach_ProcData *)NIL;
  197.     procPtr->vmPtr = vmPtr;
  198.     } else {
  199.     vmPtr = procPtr->vmPtr;
  200.     }
  201.     for (i = 0; i < VM_NUM_SEGMENTS; i++) {
  202.     vmPtr->segPtrArray[i] = (Vm_Segment *)NIL;
  203.     }
  204.     vmPtr->vmFlags = 0;
  205.     vmPtr->numMakeAcc = 0;
  206.     vmPtr->sharedSegs = (List_Links *)NIL;
  207.     VmMach_ProcInit(vmPtr);
  208. }
  209.  
  210.  
  211. /*
  212.  *----------------------------------------------------------------------
  213.  *
  214.  * Vm_RawAlloc --
  215.  *
  216.  *    Allocate bytes of memory.
  217.  *
  218.  * Results:
  219.  *    Pointer to beginning of memory allocated..
  220.  *
  221.  * Side effects:
  222.  *    Variable that indicates the end of kernel memory is modified.
  223.  *
  224.  *----------------------------------------------------------------------
  225.  */
  226. ENTRY Address
  227. Vm_RawAlloc(numBytes)
  228. int numBytes;
  229. {
  230.     Address         retAddr;
  231.     Address         maxAddr;
  232.     int         lastPage;
  233.     Vm_PTE        *ptePtr;
  234.     Vm_VirtAddr        virtAddr;
  235.     register Vm_Segment    *segPtr;
  236.  
  237.     LOCK_MONITOR;
  238.  
  239.     /*
  240.      * We return the current end of memory as our new address.
  241.      */
  242.     if (numBytes > 100 * 1024) {
  243.     printf("\nvmMemEnd = 0x%x - ", vmMemEnd);
  244.     printf("Warning: VmRawAlloc asked for >100K\n");
  245.     if (vmDebugLargeAllocs) {
  246.         Sig_SendProc(Proc_GetEffectiveProc(), SIG_DEBUG, 0, (Address)0);
  247.     }
  248.     }
  249.     retAddr = vmMemEnd;
  250.  
  251.     /*
  252.      * Bump the end of memory by the number of bytes that we just
  253.      * allocated making sure that it is four byte aligned.
  254.      */
  255. #if defined(spur) || defined(sun4)
  256.     retAddr = (Address) (((unsigned)retAddr + 7) & ~7);
  257.     vmMemEnd += (numBytes + 7) & ~7;    /* eight byte aligned for SPUR. */
  258. #else
  259. #ifdef sequent
  260.     /*
  261.      * Need 16-byte alignment on Sequent Symmetry.  See comments in
  262.      * mem/memory.c for details.
  263.      */
  264.     retAddr = (Address) (((unsigned)retAddr + 0xf) & ~0xf);
  265.     vmMemEnd += (numBytes + 0xf) & ~0xf;
  266. #else
  267.     vmMemEnd += (numBytes + 3) & ~3;
  268. #endif    
  269. #endif
  270.  
  271.     /*
  272.      * Panic if we just ran off the end of memory.
  273.      */
  274.     if (vmMemEnd > (Address) ( mach_KernStart + vmKernMemSize)) {
  275.     printf("vmMemEnd = 0x%x - ", vmMemEnd);
  276.     panic("Vm_RawAlloc: Out of memory.\n");
  277.     }
  278.  
  279.     segPtr = vm_SysSegPtr;
  280.     virtAddr.segPtr = segPtr;
  281.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  282.     virtAddr.flags = 0;
  283.     lastPage = segPtr->numPages + segPtr->offset - 1;
  284.     maxAddr = (Address) ((lastPage + 1) * vm_PageSize - 1);
  285.     ptePtr = VmGetPTEPtr(segPtr, lastPage);
  286.  
  287.     /*
  288.      * Add new pages to the virtual address space until we have added
  289.      * enough to handle this memory request.  Note that we don't allow
  290.      * VmPageAllocateInt to block if it encounters lots of dirty pages.
  291.      */
  292.     while (vmMemEnd - 1 > maxAddr) {
  293.     int    page;
  294.  
  295.     maxAddr += vm_PageSize;
  296.     lastPage++;
  297.     VmIncPTEPtr(ptePtr, 1);
  298.     virtAddr.page = lastPage;
  299.     virtAddr.offset = 0;
  300.     page = VmPageAllocateInt(&virtAddr, 0);
  301.     if (page == VM_NO_MEM_VAL) {
  302.         /*
  303.          * The normal page allocation mechanism failed so go to the
  304.          * list of pages that are held in reserve for just such an
  305.          * occasion.
  306.          */
  307.         page = VmGetReservePage(&virtAddr);
  308.         if (page == VM_NO_MEM_VAL) {
  309.         panic("VmRawAlloc: No memory available\n");
  310.         }
  311.     }
  312.     *ptePtr |= page;
  313.     VmPageValidateInt(&virtAddr, ptePtr);
  314.     segPtr->numPages++;
  315.     }
  316.  
  317.     UNLOCK_MONITOR;
  318.  
  319.     return(retAddr);
  320. }
  321.  
  322. void ChangeCodeProt();
  323.  
  324.  
  325. /*
  326.  *----------------------------------------------------------------------
  327.  *
  328.  * Vm_ChangeCodeProt --
  329.  *
  330.  *    Change the protection of the code segment for the given process.  If
  331.  *    the process still has the shared code segment then make a new 
  332.  *    copy.
  333.  *
  334.  * Results:
  335.  *    None.
  336.  *
  337.  * Side effects:
  338.  *    None.
  339.  *
  340.  *----------------------------------------------------------------------
  341.  */
  342. void
  343. Vm_ChangeCodeProt(procPtr, startAddr, numBytes, makeWriteable)
  344.     Proc_ControlBlock        *procPtr;    /* Process to change code
  345.                          * protection for. */
  346.     Address                   startAddr;    /* Beginning address of range
  347.                          * of bytes to change
  348.                          * protection.*/
  349.     int                       numBytes;    /* Number of bytes to change
  350.                          * protection for. */
  351.     Boolean            makeWriteable;    /* TRUE => make the pages 
  352.                              *     writable.
  353.                              * FALSE => make readable only*/
  354. {
  355.     register    Vm_Segment    *segPtr;
  356.     Vm_Segment    *newSegPtr;
  357.     Fs_Stream            *codeFilePtr;
  358.  
  359.     segPtr = procPtr->vmPtr->segPtrArray[VM_CODE];
  360.     if (!(segPtr->flags & VM_DEBUGGED_SEG)) {
  361.     /*
  362.      * This process still has a hold of the original shared code 
  363.      * segment.  Make a new segment for the process.
  364.      */
  365.     Fsio_StreamCopy(segPtr->filePtr, &codeFilePtr);
  366.     newSegPtr = Vm_SegmentNew(VM_CODE, codeFilePtr, segPtr->fileAddr, 
  367.                   segPtr->numPages, segPtr->offset, procPtr);
  368.     Vm_ValidatePages(newSegPtr, newSegPtr->offset, 
  369.              newSegPtr->offset + newSegPtr->numPages - 1,
  370.              FALSE, TRUE);
  371.     } else {
  372.     newSegPtr = (Vm_Segment *)NIL;
  373.     }
  374.     ChangeCodeProt(procPtr, &newSegPtr, startAddr, numBytes, makeWriteable);
  375.     if (newSegPtr != (Vm_Segment *)NIL) {
  376.     Vm_SegmentDelete(newSegPtr, procPtr);
  377.     }
  378. }
  379.  
  380.  
  381. /*
  382.  *----------------------------------------------------------------------
  383.  *
  384.  * ChangeCodeProt --
  385.  *
  386.  *    Change the protection of the code segment for the given process.
  387.  *
  388.  * Results:
  389.  *    None.
  390.  *
  391.  * Side effects:
  392.  *    None.
  393.  *
  394.  *----------------------------------------------------------------------
  395.  */
  396. ENTRY void
  397. ChangeCodeProt(procPtr, segPtrPtr, startAddr, numBytes, makeWriteable)
  398.     Proc_ControlBlock        *procPtr;    /* Process to change protection
  399.                          * for. */
  400.     Vm_Segment            **segPtrPtr;    /* IN:  New duplicated segment
  401.                          * OUT: Segment to free if 
  402.                          *      non-NIL. */
  403.     Address                   startAddr;    /* Beginning address of range
  404.                          * of bytes to change
  405.                          * protection.*/
  406.     int                       numBytes;    /* Number of bytes to change
  407.                          * protection for. */
  408.     Boolean            makeWriteable;    /* TRUE => make the pages 
  409.                              *     writable.
  410.                              * FALSE => make readable only*/
  411. {
  412.     int                firstPage;
  413.     int                lastPage;
  414.     int                i;
  415.     register    Vm_PTE        *ptePtr;
  416.     register    Vm_Segment    *segPtr;
  417.  
  418.     LOCK_MONITOR;
  419.  
  420.     segPtr = procPtr->vmPtr->segPtrArray[VM_CODE];
  421.     if (!(segPtr->flags & VM_DEBUGGED_SEG)) {
  422.     /*
  423.      * This process is currently using the shared code segment.  Use the
  424.      * private copy that our caller allocated for us and return the 
  425.      * original segment so our caller can release its reference to it.
  426.      */
  427.     segPtr = *segPtrPtr;
  428.     segPtr->flags |= VM_DEBUGGED_SEG;
  429.     *segPtrPtr = procPtr->vmPtr->segPtrArray[VM_CODE];
  430.     procPtr->vmPtr->segPtrArray[VM_CODE] = segPtr;
  431.     /*
  432.      * Free up the hardware context for this process.  When it starts
  433.      * running again new context will be setup which will have
  434.      * the new code segment in it.
  435.      */
  436.     VmMach_FreeContext(procPtr);
  437.     }
  438.  
  439.     firstPage = (unsigned int) startAddr >> vmPageShift;
  440.     lastPage = ((unsigned int) (startAddr) + numBytes - 1) >> vmPageShift;
  441.     /* 
  442.      * Make sure that the range of addresses falls into the code segment's 
  443.      * page table.  If not don't do anything.
  444.      */
  445.     if (firstPage >= segPtr->offset &&
  446.     lastPage < segPtr->offset + segPtr->ptSize) {
  447.     for (i = lastPage - firstPage, ptePtr = VmGetPTEPtr(segPtr, firstPage);
  448.          i >= 0;
  449.          i--, VmIncPTEPtr(ptePtr, 1)) {
  450.         if (makeWriteable) {
  451.         *ptePtr &= ~VM_READ_ONLY_PROT;
  452.         } else {
  453.         *ptePtr |= VM_READ_ONLY_PROT;
  454.         }
  455.     }
  456.     VmMach_SetSegProt(segPtr, firstPage, lastPage, makeWriteable);
  457.     }
  458.  
  459.     UNLOCK_MONITOR;
  460. }
  461.  
  462.  
  463. /*
  464.  *----------------------------------------------------------------------
  465.  *
  466.  * Vm_ValidatePages --
  467.  *
  468.  *    Initialize the page table for the given segment.  This involves
  469.  *    going through the software page table in the range of pages given.
  470.  *
  471.  * Results:
  472.  *    None.
  473.  *
  474.  * Side effects:
  475.  *    Page table modified for the given segment.
  476.  *
  477.  *----------------------------------------------------------------------
  478.  */
  479.  
  480. ENTRY void
  481. Vm_ValidatePages(segPtr, firstPage, lastPage, zeroFill, clobber)
  482.     Vm_Segment     *segPtr;    /* The segment whose pages are being 
  483.                  * made valid. */
  484.     int        firstPage;    /* The first page to mark valid. */
  485.     int        lastPage;    /* The last page to mark valid. */
  486.     Boolean    zeroFill;    /* Should mark pages zero fill. */
  487.     Boolean    clobber;    /* TRUE -> overwrite the pte no matter what.
  488.                  * FALSE -> only overwrite if the pte is not
  489.                  *        marked as valid in this segment's
  490.                  *        virtual address space. */
  491. {
  492.     LOCK_MONITOR;
  493.  
  494.     VmValidatePagesInt(segPtr, firstPage, lastPage, zeroFill, clobber);
  495.  
  496.     UNLOCK_MONITOR;
  497. }
  498.  
  499.  
  500. /*
  501.  *----------------------------------------------------------------------
  502.  *
  503.  * VmValidatePagesInt --
  504.  *
  505.  *    Mark as virtually resident the range of pages in the page table.
  506.  *
  507.  * Results:
  508.  *    None.
  509.  *
  510.  * Side effects:
  511.  *    Page table modified for the given segment.
  512.  *
  513.  *----------------------------------------------------------------------
  514.  */
  515. INTERNAL void
  516. VmValidatePagesInt(segPtr,  firstPage, lastPage, zeroFill, clobber)
  517.     Vm_Segment     *segPtr;    /* The segment whose page table is being 
  518.                  * initialized. */
  519.     int        firstPage;    /* The first pte to be initialized */
  520.     int        lastPage;    /* The last pte to be initialized */
  521.     Boolean    zeroFill;    /* TRUE => Mark the page as zero fill. */
  522.     Boolean    clobber;    /* TRUE -> overwrite the pte no matter what.
  523.                  * FALSE -> only overwrite if the pte is not
  524.                  *        marked as valid in this segment's
  525.                  *        virtual address space. */
  526. {
  527.     register    int    i;
  528.     register    Vm_PTE    pte;
  529.     register    Vm_PTE    *ptePtr;
  530.  
  531.     if (vm_Tracing && !(segPtr->flags & VM_SEG_CREATE_TRACED)) {
  532.     Vm_TraceSegCreate    segCreate;
  533.  
  534.     segCreate.segNum = segPtr->segNum;
  535.     segCreate.parSegNum = -1;
  536.     segCreate.segType = segPtr->type;
  537.     segCreate.cor = FALSE;
  538.     VmStoreTraceRec(VM_TRACE_SEG_CREATE_REC, sizeof(segCreate),
  539.             (Address)&segCreate, TRUE);
  540.     segPtr->flags |= VM_SEG_CREATE_TRACED;
  541.     }
  542.  
  543.     pte = VM_VIRT_RES_BIT;
  544.     if (segPtr->type == VM_CODE) {
  545.     pte |= VM_READ_ONLY_PROT;
  546.     } else if (segPtr->type == VM_SHARED) {
  547.     if (segPtr->filePtr == (Fs_Stream *)NIL) {
  548.         pte |= VM_ON_SWAP_BIT;
  549.     }
  550.     } else if (zeroFill) {
  551.     pte |= VM_ZERO_FILL_BIT;
  552.     }
  553.     for (i = firstPage, ptePtr = VmGetPTEPtr(segPtr, firstPage);
  554.      i <= lastPage;
  555.      i++, ptePtr++) {
  556.     if (clobber || !(*ptePtr & VM_VIRT_RES_BIT)) {
  557.         *ptePtr = pte;
  558.     }
  559.     }
  560. }
  561.  
  562. #ifndef symm
  563.  
  564. /*
  565.  *----------------------------------------------------------------------
  566.  *
  567.  * VmZeroPage --
  568.  *
  569.  *    External routine to fill the entire given page frame with zeroes.
  570.  *
  571.  * Results:
  572.  *    None.
  573.  *
  574.  * Side effects:
  575.  *    The page is filled with zeroes.
  576.  *
  577.  *----------------------------------------------------------------------
  578.  */
  579. void
  580. VmZeroPage(pfNum)
  581.     unsigned int    pfNum;
  582. {
  583.     register    int    mappedAddr;
  584.  
  585.  
  586.     mappedAddr = (int) VmMapPage(pfNum);
  587.     bzero((Address) mappedAddr, vm_PageSize);
  588.     VmUnmapPage((Address) mappedAddr);
  589. }
  590. #endif /* !symm */
  591.  
  592.  
  593. /*
  594.  *----------------------------------------------------------------------
  595.  *
  596.  * VmVirtAddrParse --
  597.  *
  598.  *    Take the given virtual address and fill in a virtual address struct
  599.  *    with the segment, page, and offset for this address.  If it is 
  600.  *    determined in this routine that the address does not fall in any 
  601.  *    segment then the segment that is returned is NIL.
  602.  *
  603.  * Results:
  604.  *    The translated virtual address.
  605.  *
  606.  * Side effects:
  607.  *    If the virtual address falls into a stack or heap segment then the
  608.  *    heap segment for the process is prevented from being expanded.  This
  609.  *    is to prevent another process that is sharing the heap segment from
  610.  *    changing its size and making the parsed virtual address wrong.
  611.  *
  612.  *----------------------------------------------------------------------
  613.  */
  614. ENTRY void
  615. VmVirtAddrParse(procPtr, virtAddr, transVirtAddrPtr)
  616.     Proc_ControlBlock        *procPtr;
  617.     Address            virtAddr;
  618.     register    Vm_VirtAddr    *transVirtAddrPtr;
  619. {
  620.     register    Vm_Segment        *seg1Ptr;
  621.     register    Vm_Segment        *seg2Ptr;
  622.     Vm_SegProcList            *segProcPtr;
  623.     register    int            page;
  624.  
  625.     LOCK_SHM_MONITOR;
  626.     LOCK_MONITOR;
  627.  
  628.     assert(transVirtAddrPtr != (Vm_VirtAddr *) NIL && transVirtAddrPtr != 0);
  629. #ifdef sun4
  630.     if (!VMMACH_ADDR_CHECK(virtAddr)) {
  631.     transVirtAddrPtr->segPtr = (Vm_Segment *) NIL;
  632.     UNLOCK_MONITOR;
  633.     UNLOCK_SHM_MONITOR;
  634.     return;
  635.     }
  636. #endif
  637.     transVirtAddrPtr->flags = 0;
  638.     transVirtAddrPtr->sharedPtr = (Vm_SegProcList *) NIL;
  639.     if (VmMach_VirtAddrParse(procPtr, virtAddr, transVirtAddrPtr)) {
  640.     /*
  641.      * The hardware routine was able to translate it for us.
  642.      */
  643.     UNLOCK_MONITOR;
  644.     UNLOCK_SHM_MONITOR;
  645.     return;
  646.     }
  647.  
  648.     seg1Ptr = procPtr->vmPtr->segPtrArray[VM_HEAP];
  649.     assert(seg1Ptr != (Vm_Segment *) NIL);
  650.     assert(seg1Ptr != 0);
  651.  
  652.     while (seg1Ptr->flags & VM_PT_EXCL_ACC) {
  653.     Vm_Segment    *tSegPtr;
  654.     /*
  655.      * Wait while someone has exclusive access to the page tables.
  656.      */
  657.     tSegPtr = seg1Ptr;
  658.     (void)Sync_Wait(&tSegPtr->condition, FALSE);
  659.     }
  660.     transVirtAddrPtr->offset = (unsigned int)virtAddr & (vm_PageSize - 1);
  661.  
  662.     page = (unsigned int) (virtAddr) >> vmPageShift;
  663.     transVirtAddrPtr->page = page;
  664.     assert(procPtr != (Proc_ControlBlock *) NIL && procPtr != 0);
  665.     if (procPtr->vmPtr->sharedSegs != (List_Links *)NIL &&
  666.         virtAddr >= procPtr->vmPtr->sharedStart &&
  667.         virtAddr < procPtr->vmPtr->sharedEnd) {
  668.     dprintf("VmVirtAddrParse: Checking for address %x\n",virtAddr);
  669.     segProcPtr = VmFindSharedSegment(procPtr->vmPtr->sharedSegs,virtAddr);
  670.     if (segProcPtr != (Vm_SegProcList *)NIL) {
  671.         dprintf("VmVirtAddrParse: found address in seg %x\n",
  672.             segProcPtr->segTabPtr->segPtr->segNum);
  673.         transVirtAddrPtr->segPtr = segProcPtr->segTabPtr->segPtr;
  674.         transVirtAddrPtr->flags |= (segProcPtr->prot & VM_READONLY_SEG);
  675.         transVirtAddrPtr->sharedPtr = segProcPtr;
  676.         if (transVirtAddrPtr->flags & VM_READONLY_SEG) {
  677.         dprintf("VmVirtAddrParse: (segment is readonly)\n");
  678.         }
  679.         UNLOCK_MONITOR;
  680.         UNLOCK_SHM_MONITOR;
  681.         return;
  682.     }
  683.     }
  684.  
  685.     /*
  686.      * See if the address is too large to fit into the user's virtual
  687.      * address space.
  688.      */
  689.     if (page > mach_LastUserStackPage) {
  690.     transVirtAddrPtr->segPtr = (Vm_Segment *) NIL;
  691.     UNLOCK_MONITOR;
  692.     UNLOCK_SHM_MONITOR;
  693.     return;
  694.     }
  695.     seg2Ptr = procPtr->vmPtr->segPtrArray[VM_STACK];
  696.     /*
  697.      * Check the stack segment.  Anything past the end of the heap segment 
  698.      * falls into the stack segment.  Since page tables are not allowed to
  699.      * overlap, the end of the heap segment is defined to be the end of
  700.      * the heap page table.  If it falls in the stack segment then prevent
  701.      * this process's heap segment from being expanded by incrementing the
  702.      * in use count on the page table.
  703.      */
  704.     if (page > seg1Ptr->ptSize + seg1Ptr->offset) {
  705.     assert(seg2Ptr != (Vm_Segment *) NIL && seg2Ptr != 0);
  706.     if (page < seg2Ptr->offset) {
  707.         int    newPTSize;
  708.         newPTSize = ((mach_LastUserStackPage - page)/vmPageTableInc + 1) * 
  709.                                 vmPageTableInc;
  710.         /* 
  711.          * We are going to have to grow the stack to cover this so
  712.          * make sure that the heap and stack segments don't overlap and
  713.          * we aren't trying to grow too much.
  714.          */
  715.         if ((Address) (page << vmPageShift) < seg2Ptr->minAddr ||
  716.             seg2Ptr->offset - page > vmMaxStackPagesGrowth ||
  717.             seg1Ptr->offset + seg1Ptr->ptSize >=
  718.              mach_LastUserStackPage - newPTSize + 1) {
  719.         transVirtAddrPtr->segPtr = (Vm_Segment *) NIL;
  720.         UNLOCK_MONITOR;
  721.         UNLOCK_SHM_MONITOR;
  722.         return;
  723.         }
  724.     }
  725.     transVirtAddrPtr->segPtr = seg2Ptr;
  726.     transVirtAddrPtr->flags = VM_HEAP_PT_IN_USE;
  727.     seg1Ptr->ptUserCount++;
  728.     UNLOCK_MONITOR;
  729.     UNLOCK_SHM_MONITOR;
  730.     return;
  731.     }
  732.     /* 
  733.      * Check the heap segment.  If it falls in the heap segment then prevent
  734.      * the segment from being expanded.
  735.      */
  736.     if (page >= seg1Ptr->offset && 
  737.         page < (seg1Ptr->offset + seg1Ptr->numPages)) {
  738.  
  739.     transVirtAddrPtr->segPtr = seg1Ptr;
  740.     transVirtAddrPtr->flags = VM_HEAP_PT_IN_USE;
  741.     seg1Ptr->ptUserCount++;
  742.     UNLOCK_MONITOR;
  743.     UNLOCK_SHM_MONITOR;
  744.     return;
  745.     }
  746.  
  747.     /*
  748.      * Check the code segment.
  749.      */
  750.     seg1Ptr = procPtr->vmPtr->segPtrArray[VM_CODE];
  751.     if (page >= seg1Ptr->offset &&
  752.         page < (seg1Ptr->offset + seg1Ptr->numPages)) {
  753.     transVirtAddrPtr->segPtr = seg1Ptr;
  754.     UNLOCK_MONITOR;
  755.     UNLOCK_SHM_MONITOR;
  756.     return;
  757.     }
  758.  
  759.     /*
  760.      * Doesn't fall in any segment so return NIL.
  761.      */
  762.     transVirtAddrPtr->segPtr = (Vm_Segment *) NIL;
  763.     UNLOCK_MONITOR;
  764.     UNLOCK_SHM_MONITOR;
  765.     return;
  766. }
  767.  
  768.  
  769. /*
  770.  *----------------------------------------------------------------------
  771.  *
  772.  * VmCheckBounds --
  773.  *
  774.  *    See if the given virtual address falls within the bounds of the
  775.  *    segment.  It is assumed that this segment is prevented from being
  776.  *    expanded.
  777.  *
  778.  * Results:
  779.  *    TRUE if the virtual address is in bounds.
  780.  *
  781.  * Side effects:
  782.  *    None.
  783.  *
  784.  *----------------------------------------------------------------------
  785.  */
  786. Boolean
  787. VmCheckBounds(virtAddrPtr)
  788.     register    Vm_VirtAddr    *virtAddrPtr;
  789. {
  790.     register    Vm_Segment    *segPtr;
  791.  
  792.     segPtr = virtAddrPtr->segPtr;
  793.     if (segPtr == (Vm_Segment *) NIL) {
  794.     dprintf("VmCheckBounds: NIL failure\n");
  795.     return(FALSE);
  796.     }
  797.     if (segPtr->type == VM_STACK) {
  798.     return(virtAddrPtr->page > mach_LastUserStackPage - segPtr->numPages);
  799.     } else {
  800.     if (virtAddrPtr->page - segOffset(virtAddrPtr) < 0 ||
  801.         virtAddrPtr->page - segOffset(virtAddrPtr) >
  802.         virtAddrPtr->segPtr->ptSize) {
  803.         printf("VmCheckBounds: out of bounds: page %x offset %x\n",
  804.             virtAddrPtr->page, segOffset(virtAddrPtr));
  805.         return(FALSE);
  806.     }
  807. #if 0
  808.     if (!((*VmGetAddrPTEPtr(virtAddrPtr,virtAddrPtr->page)) &
  809.         VM_VIRT_RES_BIT)) {
  810.         dprintf("VmCheckBounds: page absent failure\n");
  811.     }
  812. #endif
  813.     return ((*VmGetAddrPTEPtr(virtAddrPtr,virtAddrPtr->page)) &
  814.         VM_VIRT_RES_BIT);
  815.     }
  816. }
  817.  
  818. /*
  819.  *----------------------------------------------------------------------
  820.  *
  821.  * Vm_CopyInProc --
  822.  *
  823.  *    Copy from another processes address space into the current address
  824.  *    space. It assumed that this routine is called with the source 
  825.  *    process locked such that its VM will not go away while we are doing
  826.  *    this copy.
  827.  *
  828.  * Results:
  829.  *    SUCCESS if the copy succeeded, SYS_ARG_NOACCESS if fromAddr is invalid.
  830.  *
  831.  * Side effects:
  832.  *    What toAddr points to is modified.
  833.  *
  834.  *----------------------------------------------------------------------
  835.  */
  836. ReturnStatus
  837. Vm_CopyInProc(numBytes, fromProcPtr, fromAddr, toAddr, toKernel)
  838.     int                numBytes;    /* The maximum number of bytes
  839.                          * to copy in. */
  840.     register Proc_ControlBlock    *fromProcPtr;    /* Which process to copy from.*/
  841.     Address            fromAddr;    /* The address to copy from */
  842.     Address            toAddr;        /* The address to copy to */
  843.     Boolean            toKernel;    /* This copy is happening to 
  844.                          * the kernel's address space.*/
  845. {
  846.     ReturnStatus        status = SUCCESS;
  847.     Vm_VirtAddr            transVirtAddr;
  848.     int                lastPage;
  849.     register Proc_ControlBlock    *toProcPtr;
  850.     register Vm_Segment        **toSegPtrArr;
  851.     register int        genFlags;
  852.  
  853.     if (fromProcPtr->genFlags & PROC_NO_VM) {
  854.     /*
  855.      * The process that we are copying from has already deleted its VM.
  856.      */
  857.     return(SYS_ARG_NOACCESS);
  858.     }
  859.     toProcPtr = Proc_GetCurrentProc();
  860.     if (toProcPtr->genFlags & PROC_KERNEL) {
  861. #ifdef notdef
  862.     if (!toKernel) {
  863.         panic("Vm_CopyInProc: Kernel process not copying to kernel\n");
  864.     }
  865. #endif
  866.  
  867.     /*
  868.      * We are copying to a kernel process (an rpc server process
  869.      * hopefully).  Since we know that the process that we are copying
  870.      * from can't exit until we finish this copy we can borrow
  871.      * its address space and then just do a normal copy in.
  872.      */
  873.     toSegPtrArr = toProcPtr->vmPtr->segPtrArray;
  874.     toSegPtrArr[VM_CODE] = fromProcPtr->vmPtr->segPtrArray[VM_CODE];
  875.     toSegPtrArr[VM_HEAP] = fromProcPtr->vmPtr->segPtrArray[VM_HEAP];
  876.     toSegPtrArr[VM_STACK] = fromProcPtr->vmPtr->segPtrArray[VM_STACK];
  877.     Proc_Lock(toProcPtr);
  878.     genFlags = toProcPtr->genFlags;
  879.     genFlags &= ~PROC_KERNEL;
  880.     genFlags |= PROC_USER;
  881.     toProcPtr->genFlags = genFlags;
  882.     Proc_Unlock(toProcPtr);
  883.     VmMach_ReinitContext(toProcPtr);
  884.     status = Vm_CopyIn(numBytes, fromAddr, toAddr);
  885.     /*
  886.      * Change back into a kernel process.
  887.      */
  888.     Proc_Lock(toProcPtr);
  889.     genFlags = toProcPtr->genFlags;
  890.     genFlags &= ~PROC_USER;
  891.     genFlags |= PROC_KERNEL;
  892.     toProcPtr->genFlags = genFlags;
  893.     Proc_Unlock(toProcPtr);
  894.     toSegPtrArr[VM_CODE] = (Vm_Segment *)NIL;
  895.     toSegPtrArr[VM_HEAP] = (Vm_Segment *)NIL;
  896.     toSegPtrArr[VM_STACK] = (Vm_Segment *)NIL;
  897.     VmMach_ReinitContext(toProcPtr);
  898.     return(status);
  899.     }
  900.  
  901.     if (!toKernel && (toAddr < mach_FirstUserAddr ||
  902.                       toAddr > mach_LastUserAddr ||
  903.               toAddr + numBytes - 1 > mach_LastUserAddr)) {
  904.     /*
  905.      * The dest address is definitely not in this user process's address
  906.      * space.
  907.      */
  908.     return(SYS_ARG_NOACCESS);
  909.     }
  910.     /*
  911.      * Determine which segment the address falls into.
  912.      */
  913.     VmVirtAddrParse(fromProcPtr, fromAddr, &transVirtAddr);
  914.     if (transVirtAddr.segPtr == (Vm_Segment *)NIL) {
  915.     return(SYS_ARG_NOACCESS);
  916.     }
  917.     /*
  918.      * We now have the segment that the first address falls into, now make
  919.      * sure that the end address falls in there as well.
  920.      */
  921.     lastPage = ((unsigned int)fromAddr + numBytes - 1) / vm_PageSize;
  922.     if (transVirtAddr.segPtr->type == VM_STACK) {
  923.     if (lastPage > mach_LastUserStackPage) {
  924.         status = SYS_ARG_NOACCESS;
  925.         goto exit;
  926.     }
  927.     } else {
  928.     if (lastPage >= 
  929.         segOffset(&transVirtAddr) + transVirtAddr.segPtr->numPages) {
  930.         status = SYS_ARG_NOACCESS;
  931.         goto exit;
  932.     }
  933.     }
  934.     /*
  935.      * Call the hardware dependent routine to do the copy.
  936.      */
  937.     status = VmMach_CopyInProc(numBytes, fromProcPtr, fromAddr,
  938.                                &transVirtAddr, toAddr, toKernel);
  939.  
  940. exit:
  941.     /*
  942.      * If the source segment was a stack or heap segment then the heap
  943.      * segment was prevented from being expanded.  Let it be expanded now.
  944.      */
  945.     if (transVirtAddr.flags & VM_HEAP_PT_IN_USE) {
  946.     VmDecPTUserCount(fromProcPtr->vmPtr->segPtrArray[VM_HEAP]);
  947.     }
  948.     return(status);
  949. }
  950.  
  951.  
  952. /*
  953.  *----------------------------------------------------------------------
  954.  *
  955.  * Vm_CopyOutProc --
  956.  *
  957.  *    Copy from the current VAS to another processes VAS.  It assumed that
  958.  *    this routine is called with the dest process locked such that its 
  959.  *    VM will not go away while we are doing the copy.
  960.  *
  961.  * Results:
  962.  *    SUCCESS if the copy succeeded, SYS_ARG_NOACCESS if fromAddr is invalid.
  963.  *
  964.  * Side effects:
  965.  *    What toAddr points to is modified.
  966.  *
  967.  *----------------------------------------------------------------------
  968.  */
  969. ReturnStatus
  970. Vm_CopyOutProc(numBytes, fromAddr, fromKernel, toProcPtr, toAddr)
  971.     int                numBytes;    /* The maximum number of bytes
  972.                          * to copy in. */
  973.     Address            fromAddr;    /* The address to copy from */
  974.     Boolean            fromKernel;    /* This copy is happening to
  975.                          * the kernel's address space.*/
  976.     register Proc_ControlBlock    *toProcPtr;    /* Which process to copy from.*/
  977.     Address            toAddr;        /* The address to copy to */
  978. {
  979.     ReturnStatus        status = SUCCESS;
  980.     Vm_VirtAddr            transVirtAddr;
  981.     int                lastPage;
  982.     register Vm_Segment        *segPtr;
  983.     register Proc_ControlBlock    *fromProcPtr;
  984.     register Vm_Segment        **fromSegPtrArr;
  985.     register int        genFlags;
  986.  
  987.     if (toProcPtr->genFlags & PROC_NO_VM) {
  988.     /*
  989.      * The process that we are copying to has already deleted its VM.
  990.      */
  991.     return(SYS_ARG_NOACCESS);
  992.     }
  993.     fromProcPtr = Proc_GetCurrentProc();
  994.  
  995.     if (fromProcPtr->genFlags & PROC_KERNEL) {
  996. #ifdef notdef
  997.     if (!fromKernel) {
  998.         panic("Vm_CopyOutProc: Kernel process not copying from kernel\n");
  999.     }
  1000. #endif
  1001.  
  1002.     /*
  1003.      * We are copying to a kernel process (an rpc server process
  1004.      * hopefully).  Since we know that the process that we are copying
  1005.      * from can't exit until we finish this copy we can borrow
  1006.      * its address space and then just do a normal copy in.
  1007.      */
  1008.     fromSegPtrArr = fromProcPtr->vmPtr->segPtrArray;
  1009.     fromSegPtrArr[VM_CODE] = toProcPtr->vmPtr->segPtrArray[VM_CODE];
  1010.     fromSegPtrArr[VM_HEAP] = toProcPtr->vmPtr->segPtrArray[VM_HEAP];
  1011.     fromSegPtrArr[VM_STACK] = toProcPtr->vmPtr->segPtrArray[VM_STACK];
  1012.     Proc_Lock(fromProcPtr);
  1013.     genFlags = fromProcPtr->genFlags;
  1014.     genFlags &= ~PROC_KERNEL;
  1015.     genFlags |= PROC_USER;
  1016.     fromProcPtr->genFlags = genFlags;
  1017.     Proc_Unlock(fromProcPtr);
  1018.     VmMach_ReinitContext(fromProcPtr);
  1019.     status = Vm_CopyOut(numBytes, fromAddr, toAddr);
  1020.     /*
  1021.      * Change back into a kernel process.
  1022.      */
  1023.     Proc_Lock(fromProcPtr);
  1024.     genFlags = fromProcPtr->genFlags;
  1025.     genFlags &= ~PROC_USER;
  1026.     genFlags |= PROC_KERNEL;
  1027.     fromProcPtr->genFlags = genFlags;
  1028.     Proc_Unlock(fromProcPtr);
  1029.     fromSegPtrArr[VM_CODE] = (Vm_Segment *)NIL;
  1030.     fromSegPtrArr[VM_HEAP] = (Vm_Segment *)NIL;
  1031.     fromSegPtrArr[VM_STACK] = (Vm_Segment *)NIL;
  1032.     VmMach_ReinitContext(fromProcPtr);
  1033.     return(status);
  1034.     }
  1035.  
  1036.     if (fromProcPtr->genFlags & PROC_NO_VM) {
  1037.     /*
  1038.      * The process that we are copying from has already deleted its VM.
  1039.      */
  1040.     if (!fromKernel) {
  1041.         return(SYS_ARG_NOACCESS);
  1042.     }
  1043.     }
  1044.     /*
  1045.      * Determine which segment the address falls into.
  1046.      */
  1047.     VmVirtAddrParse(toProcPtr, toAddr, &transVirtAddr);
  1048.     if (transVirtAddr.segPtr == (Vm_Segment *)NIL) {
  1049.     return(SYS_ARG_NOACCESS);
  1050.     }
  1051.     segPtr = transVirtAddr.segPtr;
  1052.     /*
  1053.      * We now have the segment that the first address falls into, now make
  1054.      * sure that the end address falls in there as well.
  1055.      */
  1056.     lastPage = ((unsigned int)toAddr + numBytes - 1) / vm_PageSize;
  1057.     if (segPtr->type == VM_STACK) {
  1058.     if (lastPage > mach_LastUserStackPage) {
  1059.         status = SYS_ARG_NOACCESS;
  1060.         goto exit;
  1061.     }
  1062.     } else {
  1063.     if (lastPage >= segOffset(&transVirtAddr) + segPtr->numPages) {
  1064.         status = SYS_ARG_NOACCESS;
  1065.         goto exit;
  1066.     }
  1067.     }
  1068.     status = VmMach_CopyOutProc(numBytes, fromAddr, fromKernel, toProcPtr, 
  1069.                 toAddr, &transVirtAddr);
  1070.  
  1071. exit:
  1072.     /*
  1073.      * If the dest segment was a stack or heap segment then the heap
  1074.      * segment was prevented from being expanded.  Let it be expanded now.
  1075.      */
  1076.     if (transVirtAddr.flags & VM_HEAP_PT_IN_USE) {
  1077.     VmDecPTUserCount(toProcPtr->vmPtr->segPtrArray[VM_HEAP]);
  1078.     }
  1079.     return(status);
  1080. }
  1081.  
  1082.  
  1083. /*
  1084.  *----------------------------------------------------------------------
  1085.  *
  1086.  * Vm_GetKernPageFrame --
  1087.  *
  1088.  *    Return the kernel virtual page frame that is valid at the given virtual
  1089.  *    page number.  Intended to be used by the hardware specific module.
  1090.  *
  1091.  * Results:
  1092.  *    Kernel page from the page table entry.
  1093.  *
  1094.  * Side effects:
  1095.  *    None.
  1096.  *
  1097.  *----------------------------------------------------------------------
  1098.  */
  1099. unsigned int
  1100. Vm_GetKernPageFrame(pageFrame)
  1101.     int    pageFrame;
  1102. {
  1103.     Vm_PTE    *ptePtr;
  1104.     ptePtr = VmGetPTEPtr(vm_SysSegPtr, pageFrame);
  1105.     return(Vm_GetPageFrame(*ptePtr));
  1106. }
  1107.  
  1108.  
  1109. /*
  1110.  *----------------------------------------------------------------------
  1111.  *
  1112.  * Vm_KernPageAllocate --
  1113.  *
  1114.  *    Return a physical page frame.  Intended to be used by the hardware
  1115.  *    specific module.
  1116.  *
  1117.  * Results:
  1118.  *    Virtual page frame.
  1119.  *
  1120.  * Side effects:
  1121.  *    Page is taken out of the page pool.
  1122.  *
  1123.  *----------------------------------------------------------------------
  1124.  */
  1125. unsigned int
  1126. Vm_KernPageAllocate()
  1127. {
  1128.     Vm_VirtAddr    virtAddr;
  1129.  
  1130.     virtAddr.segPtr = vm_SysSegPtr;
  1131.     virtAddr.page = 0;
  1132.     return(VmPageAllocate(&virtAddr, VM_CAN_BLOCK));
  1133. }
  1134.  
  1135.  
  1136. /*
  1137.  *----------------------------------------------------------------------
  1138.  *
  1139.  * Vm_KernPageFree --
  1140.  *
  1141.  *    Free the page frame that was returned from Vm_KernPageAlloc.
  1142.  *
  1143.  * Results:
  1144.  *    None.
  1145.  *
  1146.  * Side effects:
  1147.  *    Page freed.
  1148.  *
  1149.  *----------------------------------------------------------------------
  1150.  */
  1151. void
  1152. Vm_KernPageFree(pfNum)
  1153.     unsigned    int    pfNum;
  1154. {
  1155.     VmPageFree(pfNum);
  1156. }
  1157.  
  1158.  
  1159. /*
  1160.  *----------------------------------------------------------------------
  1161.  *
  1162.  * Vm_FlushCode --
  1163.  *
  1164.  *    Flush the code at the given address from the code cache.
  1165.  *
  1166.  * Results:
  1167.  *    None.
  1168.  *
  1169.  * Side effects:
  1170.  *    None.
  1171.  *
  1172.  *----------------------------------------------------------------------
  1173.  */
  1174. ENTRY void
  1175. Vm_FlushCode(procPtr, addr, numBytes)
  1176.     Proc_ControlBlock    *procPtr;
  1177.     Address        addr;
  1178.     int            numBytes;
  1179. {
  1180.     Vm_VirtAddr    virtAddr;
  1181.     Vm_PTE    *ptePtr;
  1182.     int        lastPage;
  1183.     int        toFlush;
  1184.  
  1185.     LOCK_MONITOR;
  1186.  
  1187.     virtAddr.segPtr = procPtr->vmPtr->segPtrArray[VM_CODE];
  1188.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  1189.     virtAddr.page = (unsigned)addr >> vmPageShift;
  1190.     virtAddr.offset = (unsigned)addr & (vm_PageSize - 1);
  1191.     virtAddr.flags = 0;
  1192.     lastPage = ((unsigned)addr + numBytes - 1) >> vmPageShift;
  1193.     if (virtAddr.page >= virtAddr.segPtr->offset && 
  1194.         lastPage < virtAddr.segPtr->offset + virtAddr.segPtr->numPages) {
  1195.  
  1196.     for (ptePtr = VmGetPTEPtr(virtAddr.segPtr, virtAddr.page);
  1197.          virtAddr.page <= lastPage;
  1198.          virtAddr.page++, VmIncPTEPtr(ptePtr, 1)) {
  1199.         toFlush = vm_PageSize - virtAddr.offset;
  1200.         if (toFlush > numBytes) {
  1201.         toFlush = numBytes;
  1202.         }
  1203.         if (*ptePtr & VM_PHYS_RES_BIT) {
  1204.         VmMach_FlushCode(procPtr, &virtAddr, 
  1205.             (unsigned)(*ptePtr & VM_PAGE_FRAME_FIELD), toFlush);
  1206.         }
  1207.         numBytes -= toFlush;
  1208.         virtAddr.offset = 0;
  1209.     }
  1210.     }
  1211.  
  1212.     UNLOCK_MONITOR;
  1213. }
  1214.  
  1215.  
  1216. /*
  1217.  *----------------------------------------------------------------------
  1218.  *
  1219.  * VmFindSharedSegment --
  1220.  *
  1221.  *    Take the given virtual address and find which shared segment
  1222.  *    the address falls into.  If the address does not fall in any 
  1223.  *    shared segment then the segment that is returned is NIL.
  1224.  *
  1225.  * Results:
  1226.  *    The pointer to the shared segment list entry is returned,
  1227.  *    or NIL if none found.
  1228.  *
  1229.  * Side effects:
  1230.  *    None.
  1231.  *
  1232.  *----------------------------------------------------------------------
  1233.  */
  1234. Vm_SegProcList *
  1235. VmFindSharedSegment(sharedSegs, virtAddr)
  1236.     List_Links             *sharedSegs;
  1237.     Address            virtAddr;
  1238. {
  1239.     Vm_SegProcList    *segLinkPtr;
  1240.  
  1241.     int i=0;
  1242.  
  1243.     /*
  1244.      * Check the shared segment list.
  1245.      */
  1246.     CHECK_SHM_MONITOR;
  1247.     VmCheckListIntegrity(sharedSegs);
  1248.     LIST_FORALL(sharedSegs, (List_Links *) segLinkPtr) {
  1249.     i++;
  1250.     if (i>20) {
  1251.         dprintf("VmFindSharedSegment: loop!\n");
  1252.         break;
  1253.     }
  1254.     if (segLinkPtr->mappedStart <= virtAddr &&
  1255.         virtAddr <= segLinkPtr->mappedEnd) {
  1256.         dprintf("VmFindSharedSegment: Address is in shared segment range\n");
  1257.         return segLinkPtr;
  1258.     } else {
  1259.         dprintf("VmFindSharedSegment: Address %x outside %x %x\n",
  1260.             (int)virtAddr, (int)segLinkPtr->mappedStart,
  1261.             (int)segLinkPtr->mappedEnd);
  1262.     }
  1263.     }
  1264.     return (Vm_SegProcList *)NIL;
  1265. }
  1266.  
  1267. /*
  1268.  *----------------------------------------------------------------------
  1269.  *
  1270.  * Vm_CleanupSharedProc --
  1271.  *
  1272.  *    Remove a process's shared memory structures, for when the
  1273.  *    process exits.
  1274.  *
  1275.  * Results:
  1276.  *    None.
  1277.  *
  1278.  * Side effects:
  1279.  *    Shared memory structures associated with the process are deleted.
  1280.  *    
  1281.  *
  1282.  *----------------------------------------------------------------------
  1283.  */
  1284. void
  1285. Vm_CleanupSharedProc(procPtr)
  1286.     Proc_ControlBlock    *procPtr;    /* Process that is exiting. */
  1287. {
  1288.     int i=0;
  1289.     List_Links    *sharedSegs;    /* Process's shared segments. */
  1290.  
  1291.     LOCK_SHM_MONITOR;
  1292.     sharedSegs = procPtr->vmPtr->sharedSegs;
  1293.     while (sharedSegs != (List_Links *)NIL) {
  1294.     if (sharedSegs == (List_Links *)NULL) {
  1295.         dprintf("Vm_CleanupSharedProc: warning: sharedSegs == NULL\n");
  1296.         break;
  1297.     }
  1298.     i++;
  1299.     if (i>20) {
  1300.         dprintf("Vm_CleanupSharedProc: procExit: segment loop!\n");
  1301.         break;
  1302.     }
  1303.     if (sharedSegs==(List_Links *)NULL) {
  1304.         printf("Vm_CleanupSharedProc: Danger: null sharedSegs list\n");
  1305.         break;
  1306.     }
  1307.     if (List_IsEmpty(sharedSegs)) {
  1308.         printf("Vm_CleanupSharedProc: Danger: empty sharedSegs list\n");
  1309.         break;
  1310.     }
  1311.     if (List_First(sharedSegs)==
  1312.         (List_Links *)NULL) {
  1313.         break;
  1314.     }
  1315.     Vm_DeleteSharedSegment(procPtr,
  1316.         (Vm_SegProcList *)List_First(sharedSegs));
  1317.     }
  1318.     UNLOCK_SHM_MONITOR;
  1319. }
  1320.  
  1321. /*
  1322.  *----------------------------------------------------------------------
  1323.  *
  1324.  * Vm_DeleteSharedSegment --
  1325.  *
  1326.  *    Remove a process's mapping of a shared segment.
  1327.  *
  1328.  *      This routine removes segProcPtr from the list of shared segment
  1329.  *      mappings and frees the structure.
  1330.  *    If the process has no more references to the segment,
  1331.  *    Vm_SegmentDelete is called on the segment.  If there are no more
  1332.  *    references to the segment, it is removed from the list of shared
  1333.  *    segments.  If the process has no more shared segments, its shared
  1334.  *    segment list is freed.
  1335.  *
  1336.  * Results:
  1337.  *    None.
  1338.  *
  1339.  * Side effects:
  1340.  *    References to the segment mapping are removed.  Any unneeded data
  1341.  *    structures are unlinked and freed.
  1342.  *
  1343.  *----------------------------------------------------------------------
  1344.  */
  1345. void
  1346. Vm_DeleteSharedSegment(procPtr,segProcPtr)
  1347.     Proc_ControlBlock    *procPtr;    /* Process with mapping. */
  1348.     Vm_SegProcList        *segProcPtr;    /* Pointer to segment mapping. */
  1349. {
  1350.     Vm_SharedSegTable    *segTabPtr = segProcPtr->segTabPtr;
  1351.     Vm_Segment        *segPtr;
  1352.     Vm_VirtAddr        virtAddr;
  1353.     int            done = 0;
  1354.  
  1355.     CHECK_SHM_MONITOR;
  1356.     VmCheckListIntegrity(procPtr->vmPtr->sharedSegs);
  1357.  
  1358.     LOCK_MONITOR;
  1359.     virtAddr.page = ((int)segProcPtr->mappedStart) >> vmPageShift;
  1360.     virtAddr.segPtr = segTabPtr->segPtr;
  1361.     virtAddr.sharedPtr = segProcPtr;
  1362.     UNLOCK_MONITOR;
  1363.  
  1364.     (void) VmPageFlush(&virtAddr, segProcPtr->mappedEnd -
  1365.         segProcPtr->mappedStart + 1, FALSE, FALSE);
  1366.     List_Remove((List_Links *)segProcPtr);
  1367.     VmMach_SharedSegFinish(procPtr,segProcPtr->addr);
  1368.     if (debugVmStubs) {
  1369.     printf("Vm_DeleteSharedSegment: freeing segProcPtr %x\n", segProcPtr);
  1370.     }
  1371.     free((Address)segProcPtr);
  1372.     VmCheckListIntegrity((List_Links *)&sharedSegTable);
  1373.     /*
  1374.      * Check if this is the process's last reference to the segment.
  1375.      */
  1376.     segPtr = segTabPtr->segPtr;
  1377.     segTabPtr->refCount--;
  1378.     if (segTabPtr->refCount == 0) {
  1379.     done = 1;
  1380.     }
  1381.     if (!VmCheckSharedSegment(procPtr,segPtr)){
  1382.     dprintf("Vm_DeleteSharedSegment: Process has no more references to segment\n");
  1383.     if (List_IsEmpty(procPtr->vmPtr->sharedSegs)) {
  1384.         dprintf("Vm_DeleteSharedSegment: Process has no more shared segments\n");
  1385.         VmMach_SharedProcFinish(procPtr);
  1386.         free((Address)procPtr->vmPtr->sharedSegs);
  1387.         procPtr->vmPtr->sharedSegs = (List_Links *)NIL;
  1388.     }
  1389.     /*
  1390.      * Don't want Vm_SegmentDelete to destroy swap file unless we're
  1391.      * through with it.
  1392.      */
  1393.     segPtr->flags &= ~VM_SWAP_FILE_OPENED;
  1394.     Vm_SegmentDelete(segPtr,procPtr);
  1395.     if (!done) {
  1396.         dprintf("Vm_DeleteSharedSegment: Restoring VM_SWAP_FILE_OPENED\n");
  1397.         segPtr->flags |= VM_SWAP_FILE_OPENED;
  1398.     }
  1399.     }
  1400.     VmPrintSharedSegs(procPtr);
  1401.     dprintf("Vm_DeleteSharedSegment: done\n");
  1402.  
  1403. }
  1404.  
  1405. /*
  1406.  *----------------------------------------------------------------------
  1407.  *
  1408.  * VmCheckSharedSegment --
  1409.  *
  1410.  *    See if a process has the shared segment mapped.
  1411.  *
  1412.  * Results:
  1413.  *    TRUE if the shared segment is mapped by the process.
  1414.  *    FALSE otherwise.
  1415.  *
  1416.  * Side effects:
  1417.  *    Reads the shared memory data, so the SHM lock must be held.
  1418.  *
  1419.  *----------------------------------------------------------------------
  1420.  */
  1421. Boolean
  1422. VmCheckSharedSegment(procPtr,segPtr)
  1423.     Proc_ControlBlock    *procPtr;    /* Process to check. */
  1424.     Vm_Segment        *segPtr;    /* Pointer to shared segment. */
  1425. {
  1426.     Vm_SegProcList    *sharedSeg;
  1427.     Boolean     found=FALSE;
  1428.     /*
  1429.      * Check if segment is already on the process's list.
  1430.      */
  1431.     CHECK_SHM_MONITOR;
  1432.     dprintf("VmCheckSharedSegment: Checking if segment attached to process\n");
  1433.     VmCheckListIntegrity(procPtr->vmPtr->sharedSegs);
  1434.     LIST_FORALL(procPtr->vmPtr->sharedSegs,
  1435.         (List_Links *)sharedSeg) {
  1436.     if (sharedSeg->segTabPtr->segPtr == segPtr) {
  1437.         found = TRUE;
  1438.         break;
  1439.         }
  1440.     }
  1441.     if (found) {
  1442.     dprintf("it is\n");
  1443.     } else  {
  1444.     dprintf("it isn't\n");
  1445.     }
  1446.  
  1447.     return found;
  1448. }
  1449.  
  1450. /*
  1451.  *----------------------------------------------------------------------
  1452.  *
  1453.  * VmCheckListIntegrity --
  1454.  *
  1455.  *    See if a linked list is okay.
  1456.  *
  1457.  * Results:
  1458.  *    TRUE if the list is okay.
  1459.  *    FALSE otherwise.
  1460.  *
  1461.  * Side effects:
  1462.  *    Reads the shared memory data, so the SHM lock must be held.
  1463.  *
  1464.  *----------------------------------------------------------------------
  1465.  */
  1466. void
  1467. VmCheckListIntegrity(listHdr)
  1468.     List_Links    *listHdr;    /* Header of linked list. */
  1469. {
  1470.     int i=0;
  1471.     List_Links    *list1;
  1472.  
  1473.  
  1474.     /*
  1475.     CHECK_SHM_MONITOR;
  1476.     */
  1477.     if (List_Prev(listHdr) == (List_Links *)NULL) {
  1478.     panic("List_Prev is NULL!\n");
  1479.     }
  1480.     if (List_Prev(listHdr) == (List_Links *)NIL) {
  1481.     panic("List_Prev is NIL!\n");
  1482.     }
  1483.     if (List_Next(listHdr) == (List_Links *)NULL) {
  1484.     panic("List_Next is NULL!\n");
  1485.     }
  1486.     if (List_Next(listHdr) == (List_Links *)NIL) {
  1487.     panic("List_Next is NIL!\n");
  1488.     }
  1489.     if (List_IsEmpty(listHdr)) {
  1490.     return;
  1491.     }
  1492.  
  1493.     LIST_FORALL(listHdr,list1) {
  1494.     i++;
  1495.     if (i>10000) {
  1496.         panic("VmCheckListIntegrity: too long\n");
  1497.     }
  1498.     if (List_Next(List_Prev(list1))!=list1) {
  1499.         panic("VmCheckListIntegrity: error\n");
  1500.     }
  1501.     if (List_Prev(List_Next(list1))!=list1) {
  1502.         panic("VmCheckListIntegrity: error\n");
  1503.     }
  1504.     }
  1505. }
  1506.  
  1507. /*
  1508.  *----------------------------------------------------------------------
  1509.  *
  1510.  * VmPrintSharedSegs --
  1511.  *
  1512.  *    Print info on the shared segments for a proc.
  1513.  *
  1514.  * Results:
  1515.  *    None.
  1516.  *
  1517.  * Side effects:
  1518.  *    Reads the shared memory data, so the SHM lock must be held.
  1519.  *
  1520.  *----------------------------------------------------------------------
  1521.  */
  1522. void
  1523. VmPrintSharedSegs(procPtr)
  1524.     Proc_ControlBlock    *procPtr;    /* Process to check. */
  1525. {
  1526.     Vm_SegProcList        *procListPtr;
  1527.     Vm_SharedSegTable    *segTabPtr;
  1528.  
  1529.     CHECK_SHM_MONITOR;
  1530.     dprintf("VmPrintSharedSegs: info for %x (%x)\n",(int)procPtr,
  1531.         (int)procPtr->processID);
  1532.     dprintf("  Shared Segment Table:\n");
  1533.     LIST_FORALL((List_Links *)&sharedSegTable,(List_Links *)segTabPtr) {
  1534.     dprintf("  entry: %x fileNumber: %d refcount: %d segPtr: %x segNum: %d\n",
  1535.         (int)segTabPtr,segTabPtr->fileNumber, segTabPtr->refCount,
  1536.         (int)segTabPtr->segPtr,segTabPtr->segPtr->segNum);
  1537.     }
  1538.     if (procPtr->vmPtr->sharedSegs == (List_Links *)NIL) {
  1539.     dprintf("  Process list: NIL\n");
  1540.     } else {
  1541.     dprintf("  Proc: %x (%x):\n",(int)procPtr,procPtr->processID);
  1542.     LIST_FORALL(procPtr->vmPtr->sharedSegs,(List_Links *)procListPtr) {
  1543.         dprintf("  fd: %d table: %x address: %x start: %x end: %x\n",
  1544.             (int)procListPtr->fd, procListPtr->segTabPtr,
  1545.             (int)procListPtr->addr, (int)procListPtr->mappedStart,
  1546.             (int)procListPtr->mappedEnd);
  1547.     }
  1548.     }
  1549. }
  1550.  
  1551. /*
  1552.  *----------------------------------------------------------------------
  1553.  *
  1554.  * Vm_CleanupSharedFile --
  1555.  *
  1556.  *    Delete segments associated with a file stream.
  1557.  *    This routine calls Vm_DeleteSharedSegment on the segments
  1558.  *    associated with the file stream.
  1559.  *
  1560.  * Results:
  1561.  *    None.
  1562.  *
  1563.  * Side effects:
  1564.  *    Shared segments are deleted.
  1565.  *    Uses the SHM lock.
  1566.  *
  1567.  *----------------------------------------------------------------------
  1568.  */
  1569. /*ARGSUSED*/
  1570. void
  1571. Vm_CleanupSharedFile(procPtr,streamPtr)
  1572.     Proc_ControlBlock    *procPtr;    /* Process with file. */
  1573.     Fs_Stream        *streamPtr;    /* Stream to remove. */
  1574. {
  1575.     Vm_SegProcList        *segPtr;
  1576.     Vm_SegProcList        *nextPtr;
  1577.     List_Links            *sharedSegs = procPtr->vmPtr->sharedSegs;
  1578.  
  1579.     LOCK_SHM_MONITOR;
  1580.     if (procPtr->vmPtr->sharedSegs != (List_Links *)NIL) {
  1581.     for (segPtr=(Vm_SegProcList *)List_First(sharedSegs);
  1582.         !List_IsAtEnd(sharedSegs,(List_Links *)segPtr);
  1583.         segPtr=nextPtr) {
  1584.         nextPtr = (Vm_SegProcList *)List_Next((List_Links *)segPtr);
  1585.         if (segPtr->stream==streamPtr) {
  1586.         dprintf("sharedSegment being deleted in Vm_CleanupSharedFile\n");
  1587. #if 0
  1588.         Vm_DeleteSharedSegment(procPtr,segPtr);
  1589. #else
  1590.         if (debugVmStubs) {
  1591.             printf("Vm_CleanupSharedFile: skipping segment delete\n");
  1592.         }
  1593. #endif
  1594.         if (sharedSegs == (List_Links *)NIL) {
  1595.             break;
  1596.         }
  1597.         }
  1598.     }
  1599.     }
  1600.     UNLOCK_SHM_MONITOR;
  1601. }
  1602.  
  1603. /*
  1604.  * ----------------------------------------------------------------------------
  1605.  *
  1606.  * Vm_CopySharedMem --
  1607.  *
  1608.  *     Copies shared memory data structures to handle a fork.
  1609.  *
  1610.  * Results:
  1611.  *     None.
  1612.  *
  1613.  * Side effects:
  1614.  *     The new process gets a copy of the shared memory structures.
  1615.  *
  1616.  * ----------------------------------------------------------------------------
  1617.  */
  1618. void
  1619. Vm_CopySharedMem(parentProcPtr, childProcPtr)
  1620.     Proc_ControlBlock    *parentProcPtr;    /* Parent process. */
  1621.     Proc_ControlBlock    *childProcPtr;    /* Child process. */
  1622. {
  1623.     Vm_Segment *segPtr;
  1624.     Vm_SegProcList *sharedSeg;
  1625.     Vm_SegProcList *parentSeg;
  1626.     LOCK_SHM_MONITOR;
  1627.     if (parentProcPtr->vmPtr->sharedSegs != (List_Links *)NIL) {
  1628.     childProcPtr->vmPtr->sharedSegs = (List_Links *)
  1629.         malloc(sizeof(Vm_SegProcList));
  1630.     List_Init((List_Links *)childProcPtr->vmPtr->sharedSegs);
  1631.     LIST_FORALL(parentProcPtr->vmPtr->sharedSegs,
  1632.         (List_Links *)parentSeg) {
  1633.         sharedSeg = (Vm_SegProcList *)malloc(sizeof(Vm_SegProcList));
  1634.         bcopy((Address)parentSeg, (Address)sharedSeg,
  1635.             sizeof(Vm_SegProcList));
  1636.         segPtr = sharedSeg->segTabPtr->segPtr;
  1637.         if(!VmCheckSharedSegment(childProcPtr, segPtr)) {
  1638.         Vm_SegmentIncRef(segPtr, childProcPtr);
  1639.         }
  1640.         segPtr->refCount++;
  1641.         List_Insert((List_Links *)sharedSeg,
  1642.             LIST_ATREAR((List_Links *)childProcPtr->vmPtr->sharedSegs));
  1643.     }
  1644.     VmMach_CopySharedMem(parentProcPtr, childProcPtr);
  1645.     }
  1646.     UNLOCK_SHM_MONITOR;
  1647. }
  1648.